iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Modern Web

Phoenix 1.7 完全教學系列 第 22

22 LiveView 生命週期

  • 分享至 

  • xImage
  •  

相對於之前做的 Controller-View,LiveView 會一直有一個 process 在維護頁面的狀態,有狀態代表有一個週期循環。

LiveView 流程

1. router

與 Controller-View 一樣,LiveView 也是由 router 出發,當相對應的網址被匹配到時,就會執行對應的 LiveView。
如我們上一篇的

live "/demo", DemoLive

就是當網址是 /demo 時,執行 DemoLive 這個 LiveView module。

2. mount

當執行 LiveView module 時,會先呼叫 module 裡面的 mount 函式,mount 函式是一個 callback,要由我們主動定義,這個 callback 函式的預期回覆是 {:ok, socket}
如上一篇的

def mount(_params, _session, socket) do
  {:ok, assign(socket, message: "第一個 LiveView 頁面!", card: "🂠")}
end

通常我們會在在這邊把之後需要的起始值 assign 到 socket 裡面 (使用 assign)
(雖然很少這麼做但是這個 mount callback 是可以忽略的,等同於不更改 socket 的內容直接回傳原本的 socket {:ok, socket})

3. handle_params

有時候需要處理網址上的 query 參數,都會在這邊處理,如果不需要可以忽略。
例如目前網頁的頁數:

# 網址: "/notes?page=3"
def handle_params(params, _uri, socket) do
  page = Map.get(params, "page", 1)
  socket = assign(socket, notes: list_notes_by_page(page))

  {:noreply, socket}
end

或是搜尋的條件:

# 網址: "/notes?search=elixir"
def handle_params(%{search: search} = params, _uri, socket) do
  socket = assign(socket, notes: list_notes_by_title(search))

  {:noreply, socket}
end

4. render

在這邊我們把先前組出來的 assigns 鑲嵌到 html template 裡面,並回傳給前端。

def render(assigns) do
  ~H"""
  <h1><%= @title %></h1>
  """
end

在瀏覽器收到的當下,這個網頁都還只是靜態的,直到瀏覽器開始執行 LiveView 內建的 javascript 便開始要求伺服器使用 websocket 來同步頁面。

5. websocket

收到 LiveView 的 Websocket 要求時,Phoenix 會再度執行這些步驟並產生同一個頁面。

  • mount
  • handle_params
  • render

第二次的得到畫面之後,會與第一次的畫面做比較,並把不同的部分傳給前端,前端再把這些差異的部分更新到畫面上。

6. 畫面狀態在伺服器端

從這邊開始,畫面都由伺服器端的 assigns 狀態來決定。如果畫面需要更改,只需要修改在各個動作回傳的 socket assigns,每一次 assigns 改變時,LiveView 都會自動檢查,並把差異的部分透過 websocket 傳給前端。

例如上一篇的抽卡按鈕
我們在 <.button phx-click="random_card">抽一張牌</.button> 裡面的 phx-click 在觸發時會發送 LiveView 到伺服器,伺服器會執行 handle_event 這個 callback,並回傳新的 assigns 給前端。

def handle_event("random_card", _params, socket) do
  {:noreply, assign(socket, card: new_card())}
end

或者是,如果有從伺服器開始的事件,例如我想要在 5 秒後自動抽卡,我們可以在 mount 時使用 send_after 來設定一個計時計。

def mount(_params, _session, socket) do
  send_after(self(), :auto_draw, 5000) # 加這行
  {:ok, assign(socket, message: "第一個 LiveView 頁面!", card: "🂠")}
end

這樣子在五秒後,就會發送一個 :auto_draw 事件給自己(self() 回傳目前這個 LiveView process 的 pid)

增加一個 handle_info 裡面處理這個 process 事件

def handle_info(:auto_draw, socket) do
  {:noreply, assign(socket, card: new_card())}
end

這樣一來,五秒之後就會自動觸發 :auto_draw 事件,並更新畫面。


上一篇
21 LiveView 簡單的互動頁面
下一篇
23 LiveView Index 頁面
系列文
Phoenix 1.7 完全教學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言